package com.greenhou.executor;

import com.greenhou.mapping.BoundSql;
import com.greenhou.pojo.Configuration;
import com.greenhou.pojo.MappedStatement;
import com.greenhou.utils.GenericTokenParser;
import com.greenhou.utils.ParameterMapping;
import com.greenhou.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName SimpleExecutor
 * @Description 默认执行器
 * @Author YR
 * @Date 2020/6/15 21:56
 * @Version 1.0
 */
public class SimpleExecutor implements Executor{
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        //1 获取连接
        Connection connection=configuration.getDataSource().getConnection();
        //2 解析sql，处理sql里边的参数#{property}
        String sql=mappedStatement.getSql();
        BoundSql boundSql=this.getBoundSql(sql);
        //3 通过prepareStatement 处理参数问题
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        List<ParameterMapping> parameterMappingList=boundSql.getParameterMappingList();
        if(parameterMappingList!=null && parameterMappingList.size()>0 && params!=null && params.length>0){
            String parameterType=mappedStatement.getParameterType();
            Class parameterClass=Class.forName(parameterType);
            for(int i=0;i<parameterMappingList.size();i++){
                Field parameterField = parameterClass.getDeclaredField(parameterMappingList.get(i).getContent());
                //允许绕过验证  访问
                parameterField.setAccessible(true);
                preparedStatement.setObject(i+1,parameterField.get(params[0]));
            }
        }
        //4执行sql语句
        ResultSet resultSet = preparedStatement.executeQuery();
        //5处理返回结果集 封装到对象
        if(resultSet==null){
            return null;
        }
        String resultType=mappedStatement.getResultType();
        Class resultTypeClass=Class.forName(resultType);
        List<E> resultList=new ArrayList<>();
        while (resultSet.next()){
            ResultSetMetaData metaData = resultSet.getMetaData();

            Object resultObject=resultTypeClass.newInstance();
            int rowCount=metaData.getColumnCount();
            for(int i=1;i<=rowCount;i++){
                String columnName = metaData.getColumnName(i);

                //反射
//                Field field=resultTypeClass.getDeclaredField(columnName);
//                field.setAccessible(true);
//                field.set(resultObject,resultSet.getObject(columnName));
                //内省
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(resultObject,resultSet.getObject(columnName));
            }
            resultList.add((E) resultObject);
        }
        return resultList;
    }

    private BoundSql getBoundSql(String sql) {
        ParameterMappingTokenHandler handler=new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser=new GenericTokenParser("#{","}",handler);
        String sqlText=genericTokenParser.parse(sql);
        //构建返回对象
        BoundSql boundSql=new BoundSql();
        boundSql.setSqlText(sqlText);
        boundSql.setParameterMappingList(handler.getParameterMappings());
        return boundSql;
    }
}
